import cn.hutool.core.util.RuntimeUtil;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.win32.StdCallLibrary;
import lombok.extern.slf4j.Slf4j;
import reactor.util.function.Tuple4;
import reactor.util.function.Tuples;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;

@Slf4j
public class SwitchScreen {
    public interface User32 extends StdCallLibrary {
        User32 INSTANCE = Native.load("user32", User32.class);

        boolean EnumWindows(WinUser.WNDENUMPROC lpEnumFunc, Pointer arg);

        int GetWindowTextA(HWND hWnd, byte[] lpString, int nMaxCount);

        boolean SetForegroundWindow(HWND hWnd);

        boolean ShowWindow(HWND hWnd, int nCmdShow);
    }

    public static void main(String[] args) {
        setFrontBrowser(args[0]);
    }

    /**
     * 2.1 设置前景浏览器
     *
     * @param title 浏览器标题
     */
    private static void setFrontBrowser(String title) {
        HWND hwnd = getHandler(title);
        boolean a = User32.INSTANCE.ShowWindow(hwnd, 1);
        boolean b = User32.INSTANCE.SetForegroundWindow(hwnd);
        log.info("设置前景浏览器 {} - {} - {}", title, a, b);
    }

    /**
     * 2.2 获取浏览器进程/句柄
     * @param title 浏览器标题
     * @return 进程/句柄
     */
    private static HWND getHandler(String title) {
        AtomicReference<HWND> hwnd0 = new AtomicReference<>();
        User32.INSTANCE.EnumWindows((hwnd, pointer) -> {
            byte[] windowText = new byte[512];
            User32.INSTANCE.GetWindowTextA(hwnd, windowText, 512);
            String wText = Native.toString(windowText);
            getHwndBySTitle().accept(Tuples.of(wText, title, hwnd0, hwnd));
            return true;
        }, null);
        return hwnd0.get();
    }

    /**
     * 2.3 具体逻辑
     * @return
     */
    private static Consumer<Tuple4<String, String, AtomicReference<HWND>, HWND>> getHwndBySTitle() {
        return tp4 -> {
            if (!tp4.getT1().isEmpty() && tp4.getT1().contains(tp4.getT2())) {
                log.info("捕捉到浏览器 {}", tp4.getT1());
                tp4.getT3().set(tp4.getT4());
            } else {
                log.trace("过滤掉的进程 {}", tp4.getT1());
            }
        };
    }


    public void init() {
        RuntimeUtil.execForStr("start aaa.bat");
        Set<String> set = new HashSet<String>() {{
            add("OPLPage");
            add("SPLPage");
        }};
        Timer timer = new Timer();
        AtomicInteger count = new AtomicInteger(0);
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                Map<String, HWND> map = getHandler(set);
                if (map.keySet().size() == 2) {
                    HWND hwnd = map.get("OPLPage");
                    User32.INSTANCE.ShowWindow(hwnd, 1);
                    User32.INSTANCE.SetForegroundWindow(hwnd);
                    this.cancel();
                } else {
                    if (count.incrementAndGet() > 10) {
                        this.cancel();
                        timer.cancel();
                    } else {
                        System.out.println("初始化任务执行中 " + count.get());
                    }

                }
            }
        }, 0, 1000);
    }

    private static Map<String, HWND> getHandler(Set<String> set) {
        Map<String, HWND> map = new HashMap<>();
        User32.INSTANCE.EnumWindows((hwnd, pointer) -> {
            byte[] windowText = new byte[512];
            User32.INSTANCE.GetWindowTextA(hwnd, windowText, 512);
            String wText = Native.toString(windowText);
            if (wText.isEmpty()) {
                return true;
            }
            set.forEach(it -> {
                if (wText.contains(it)) {
                    map.put(it, hwnd);
                    log.info("Found window with text " + hwnd + ", total " + " Text: " + wText);
                }
            });
            return true;
        }, null);
        return map;
    }
}
